/**
 * 
 */
package net.toocruel.iqismart.service.core.impl;


import net.toocruel.iqismart.dao.condition.TagCondition;
import net.toocruel.iqismart.dao.condition.TopicsCondition;
import net.toocruel.iqismart.dao.core.CategoryRepository;
import net.toocruel.iqismart.dao.core.TagRepository;
import net.toocruel.iqismart.dao.spec.TagSpec;
import net.toocruel.iqismart.entity.common.Category;
import net.toocruel.iqismart.entity.common.Tag;
import net.toocruel.iqismart.service.core.TagService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author toocruel
 *
 */
@Service
@Transactional
public class TagServiceImpl implements TagService {
    @Autowired
    private TagRepository tagRepository;

    @Autowired
    private CategoryRepository categoryRepository;

    public Page<Tag> query(TagCondition condition, Pageable pageable) {
        return tagRepository.findAll(new Specification<Tag>() {
            @Override
            public Predicate toPredicate(Root<Tag> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();

                if (StringUtils.isNotBlank(condition.getNameStart())) {
                    predicates.add(cb.like(root.get("name"), "%" + condition.getNameStart() + "%"));
                }

                if (StringUtils.isNotBlank(condition.getName())) {
                    predicates.add(cb.equal(root.get("name"), condition.getName()));
                }

                if(condition.getCategoryId()==null || condition.getCategoryId() == 0){
                    predicates.add(cb.isNull(root.get("category")));
                }else {
                    predicates.add(cb.equal(root.get("category"), condition.getCategoryId()));
                }



                return cb.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        }, pageable);

//        return tagRepository.findAll(new TagSpec(condition),pageable);
    }

    public Set<Tag> query(TagCondition condition) {
        return tagRepository.findAll(new TagSpec(condition)).stream().collect(Collectors.toSet());
    }

    @Override
    public Set<Tag> findAndCreateIfNotExist(Long categoryId, String tagNames) {

        if(categoryId!=null && categoryId == 0){
            categoryId = null;
        }

        if(StringUtils.isNotBlank(tagNames)){
            Set<Tag> tags = new HashSet<>();
            String[] split = tagNames.split(",");
            Long finalCategoryId = categoryId;
            Arrays.stream(split).forEach(name->{
                Tag tag = null;
                try {
                    List<Tag> tagList = tagRepository.findAll((root, query, cb) -> {
                        Predicate p1 = cb.equal(root.get("name"), name);
                        Predicate p2 = null;
                        if(finalCategoryId == null){
                            p2 = cb.isNull(root.get("category"));
                        }else{
                            p2 = cb.equal(root.get("category"), finalCategoryId);
                        }
                        return cb.and(p1,p2);
                    });

                    if(CollectionUtils.isNotEmpty(tagList)){
                        tag = tagList.get(0);
                        if(tagList.size()>1){
                            tagList.subList(1,tagList.size()).forEach(item->{
                                tagRepository.delete(item);
                            });

                        }
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
                if(tag == null){
                    Tag entity = new Tag(name);
                    if(finalCategoryId!=null){
                        entity.setCategory(categoryRepository.findOne(finalCategoryId));
                    }
                    tag =  tagRepository.save(entity);
                }
                tags.add(tag);
            });
            return tags;
        }
        return null;
    }

    @Override
    public List<Tag> findAll() {
        return tagRepository.findAll();
    }

    @Override
    public List<Tag> getHotTags(int count) {
        List<Tag> hotTags = new ArrayList<>();
        List<Object[]> hotTagObjects = tagRepository.getHotTags(count);
        hotTagObjects.forEach(hotTagObject->{
            Tag tag = new Tag();
            tag.setId(Long.parseLong(hotTagObject[0]+""));
            tag.setName(hotTagObject[1]+"");
            tag.setQuestions(Integer.parseInt(hotTagObject[2]+""));
            hotTags.add(tag);
        });
        return hotTags;
    }

    @Override
    public Page<Tag> findAll(TopicsCondition condition, PageRequest pageRequest) {
        String categorySlug = condition.getCategorySlug();
        Long categoryId = condition.getCategoryId();

        Page<Tag> tags = tagRepository.findAll((root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            //页面用标签id来传参
            if (categoryId != null && categoryId > 0) {
                Category category = categoryRepository.findOne(categoryId);
                condition.setCategory(category);
                predicates.add(cb.equal(root.get("category"), category));
            }

            //页面用标签slug来传参
            if (StringUtils.isNotBlank(categorySlug)) {
                Category category = categoryRepository.findBySlug(categorySlug);
                condition.setCategory(category);
                predicates.add(cb.equal(root.get("category"), category));
            }





            //TODO

            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
        }, pageRequest);




        return tags;
    }
}
